package com.gelingqin.es.springbootdemo.service;

import java.io.IOException;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import ch.qos.logback.core.net.SyslogOutputStream;
import com.gelingqin.es.springbootdemo.core.ElasticsearchClientFactory;
import com.gelingqin.es.springbootdemo.entity.Query;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.nio.entity.NStringEntity;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.aggregations.bucket.histogram.ParsedDateHistogram;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

/**
 * es服务
 * 
 * @author 86133
 *
 */

@Slf4j
@Service
public class ElasticsearchService {

	@Autowired
	private ElasticsearchClientFactory elasticsearchClientFactory;

	private RestHighLevelClient restHighLevelClient;
	private RestClient restClient;

	/**
	 * 初始化客户端
	 */
	@PostConstruct
	public void init() {
		restHighLevelClient = elasticsearchClientFactory.getRestHighLevelClient();
		if (restHighLevelClient!=null) {
			restClient=restHighLevelClient.getLowLevelClient();
			
		}
		
	}

	public List<Map<String, Object>> search(Query query) {
		List<Map<String, Object>> rList = new ArrayList<Map<String, Object>>();
		QueryBuilder queryBuilder = queryBuilder(query);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.query(queryBuilder);
		HighlightBuilder highlightBuilder = new HighlightBuilder();
		highlightBuilder.field("content", 20480, 1);
		// html开始标签
		highlightBuilder.preTags("<span style=\"background:yellow;font-weight:bold;\">");
		// html结束标签
		highlightBuilder.postTags("</span>");
		highlightBuilder.requireFieldMatch(true);
		searchSourceBuilder.highlighter(highlightBuilder);
		// 设置查询索引
		SearchRequest searchRequest = new SearchRequest(query.getIndexPattern());
		searchRequest.source(searchSourceBuilder);
		// 执行查询，然后处理响应结果
		SearchResponse searchResponse;
		try {
			searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			// 根据状态和数据条数验证是否返回了数据
			if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().getHits().length > 0) {
				SearchHits hits = searchResponse.getHits();
				for (SearchHit hit : hits) {
					Map<String, Object> map=hit.getSourceAsMap();

					// 输出查询信息
					Map<String, HighlightField> rhighlightFields = hit.getHighlightFields();
					if (rhighlightFields.size() > 0) {
						HighlightField field = rhighlightFields.get("content");
						String fieldContent = "";
						if (field != null) {
							Text[] fragments = field.fragments();
							for (Text text : fragments) {
								fieldContent += text;
								map.put("content", fieldContent);
							}
							System.out.println(fieldContent);
						}
					}
					rList.add(map);

				}
			}
		} catch (IOException e) {
			log.error("查询失败", e);
			// TODO 跑出业务异常

		}
		return rList;

	}
	public List<Map<String, Object>> dateHistgram(Query query) {
		QueryBuilder queryBuilder = queryBuilder(query);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		searchSourceBuilder.query(queryBuilder);
		DateHistogramAggregationBuilder dateHistogramAggregationBuilder = AggregationBuilders
				.dateHistogram("groupDate")
				.field("@timestamp")
				.calendarInterval(DateHistogramInterval.DAY)
				.format("yyyy-MM-dd")
				.offset("-8h")
				.timeZone(ZoneId.of("CTT"))
				.minDocCount(0);
		searchSourceBuilder.aggregation(dateHistogramAggregationBuilder);
		// 设置查询索引
		SearchRequest searchRequest = new SearchRequest(query.getIndexPattern());
		searchRequest.source(searchSourceBuilder);
		// 执行查询，然后处理响应结果
		SearchResponse searchResponse;
		try {
			searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
			ParsedDateHistogram parsedDateHistogram=searchResponse.getAggregations().get("groupDate");
			for (Histogram.Bucket bucket : parsedDateHistogram.getBuckets()) {
				System.out.println("日期："+bucket.getKeyAsString()+"总数:"+bucket.getDocCount());
			}

		}catch (IOException e) {
			log.error("查询失败", e);
			// TODO 抛出业务异常

		}

		return  null;

	}

	/**
	 * rest接口查詢
	 * @param method
	 * @param endpoint
	 * @param param
	 * @param clazz
	 * @param <T>
	 * @return
	 */
	public <T> T performRequest(String method,String endpoint,Object param,Class<T> clazz){
		Request request = new Request(method,  endpoint);
		if (param!=null){
			HttpEntity entity = new NStringEntity(JSON.toJSONString(param), ContentType.APPLICATION_JSON);
			request.setEntity(entity);
		}
		Response response;
		try {
			response = restClient.performRequest(request);
			String json=EntityUtils.toString(response.getEntity());
			return JSON.parseObject(json,clazz);
		} catch (IOException e) {
			log.error("查询失败", e);
			// TODO 抛出业务异常
		}
		return null;
	}

	public Map ilmPolicyAll() {
		Request request = new Request("GET",  "/_ilm/policy");  
		Response response;
		try {
			response = restClient.performRequest(request);
			String responseBody = EntityUtils.toString(response.getEntity());
			return JSON.parseObject(responseBody, Map.class);
		} catch (IOException e) {
			log.error("查询失败", e);
			// TODO 跑出业务异常
		}
		return null;
	}

	/**
	 * 构建es查询
	 * 
	 * @param query
	 * @return
	 */
	private QueryBuilder queryBuilder(final Query query) {
		final BoolQueryBuilder bool = QueryBuilders.boolQuery();
		final List<QueryBuilder> musts = (List<QueryBuilder>) query.getMusts();
		final List<QueryBuilder> filters = (List<QueryBuilder>) query.getFilters();
		final List<QueryBuilder> mustNots = (List<QueryBuilder>) query.getMustNots();
		final List<QueryBuilder> shoulds = (List<QueryBuilder>) query.getShoulds();
		for (final QueryBuilder must : musts) {
			bool.must(must);
		}
		for (final QueryBuilder mustNot : mustNots) {
			bool.mustNot(mustNot);
		}
		for (final QueryBuilder should : shoulds) {
			bool.should(should);
		}
		for (final QueryBuilder filter : filters) {
			bool.filter(filter);
		}
		return (QueryBuilder) bool;
	}

}
